package com.dmai.capacity.platform.gateway.filter;

import com.dmai.capacity.platform.log.properties.TraceProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;

@Slf4j
@Configuration
@ConditionalOnProperty(value = "dmai.trace.enabled", havingValue = "true", matchIfMissing = true)
public class RequestLogFilter implements GlobalFilter, Ordered {

    @Autowired
    private TraceProperties traceProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().value();
        String method = request.getMethod().toString();
        HttpHeaders header = request.getHeaders();

        log.info("request：method = {}，path = {}", method, path);
        if (traceProperties.getRequestParam()) {
            if ("POST".equals(method) || "PUT".equals(method) || "PATCH".equals(method)) {
                return DataBufferUtils.join(exchange.getRequest().getBody())
                        .flatMap(dataBuffer -> {
                            byte[] bytes = new byte[dataBuffer.readableByteCount()];
                            dataBuffer.read(bytes);
                            try {
                                String bodyString = new String(bytes, "utf-8");
                                log.info("bodyParams：" + bodyString);
                                exchange.getAttributes().put("POST_BODY", bodyString);
                            } catch (UnsupportedEncodingException e) {
                                e.printStackTrace();
                            }
                            DataBufferUtils.release(dataBuffer);
                            Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                                DataBuffer buffer = exchange.getResponse().bufferFactory()
                                        .wrap(bytes);
                                return Mono.just(buffer);
                            });

                            ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                    exchange.getRequest()) {
                                @Override
                                public Flux<DataBuffer> getBody() {
                                    return cachedFlux;
                                }
                            };
                            return chain.filter(exchange.mutate().request(mutatedRequest).build());
                        });
            } else if ("GET".equals(method)) {
                MultiValueMap<String, String> queryParams = request.getQueryParams();
                log.info("queryParams：" + queryParams);
                return chain.filter(exchange);
            }
        }
        return chain.filter(exchange);
    }


    @Override
    public int getOrder() {
        return -3;
    }
}